package com.houning.rsa;

import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSADemo {
    public static void main(String[] args) throws Exception {
        String input = "硅谷";
        // 创建密钥对
        String algorithm = "RSA";

        // 读取私钥
        PrivateKey privateKey = getPrivateKey("a.pri", algorithm);
        System.out.println(privateKey);

        // 读取公钥
        PublicKey publicKey = getPublicKey("a.pub", algorithm);
        System.out.println(publicKey);


        // 生成密钥对并保存在本地文件中
//        generateKeyToFile(algorithm, "a.pub", "a.pri");

//        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
//        // 生成密钥对
//        KeyPair keyPair = keyPairGenerator.generateKeyPair();
//        // 生成私钥
//        PrivateKey privateKey = keyPair.getPrivate();
//        // 生成公钥
//        PublicKey publicKey = keyPair.getPublic();
//        // 获取私钥的字节数组
//        byte[] privateKeyEncoded = privateKey.getEncoded();
//        // 获取公钥字节数组
//        byte[] publicKeyEncoded = publicKey.getEncoded();
//        // 使用base64进行编码
//        Base64.Encoder encoder = Base64.getEncoder();
//        String privateEncodeString = encoder.encodeToString(privateKeyEncoded);
//        String publicEncodeString = encoder.encodeToString(publicKeyEncoded);
//        // 打印公钥和私钥
//        System.out.println(privateEncodeString);
//        System.out.println(publicEncodeString);

//        // 创建加密对象
//        Cipher cipher = Cipher.getInstance(algorithm);
//        // 对加密进行初始化
//        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
//        // 使用私钥进行加密
//        byte[] bytes = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
//        String encoded = Base64.getEncoder().encodeToString(bytes);
//        System.out.println(encoded);
//
//
//        // 私钥解密
//        cipher.init(Cipher.DECRYPT_MODE, publicKey);
//        // 使用私钥进行解密
//        byte[] decrypted = cipher.doFinal(bytes);
//        System.out.println(new String(decrypted, StandardCharsets.UTF_8));


//        String encrypted = encryptRSA(algorithm, privateKey, input);
//        System.out.println(encrypted);
//
//        String decrypted = decryptRSA(algorithm, publicKey, encrypted);
//        System.out.println(decrypted);
    }

    /**
     * 读取公钥
     *
     * @param publicPath 公钥路径
     * @param algorithm  算法
     * @return 公钥key对象
     */
    public static PublicKey getPublicKey(String publicPath, String algorithm) throws Exception {
        String publicKeyString = FileUtils.readFileToString(new File(publicPath), StandardCharsets.UTF_8);
        // 创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        byte[] decoded = Base64.getDecoder().decode(publicKeyString);
        // 创建公钥规则
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 读取私钥
     *
     * @param priPath   私钥的路径
     * @param algorithm 算法
     * @return 返回私钥的key对象
     */
    public static PrivateKey getPrivateKey(String priPath, String algorithm) throws Exception {
        String privateKeyString = FileUtils.readFileToString(new File(priPath), StandardCharsets.UTF_8);
        // 创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        byte[] decoded = Base64.getDecoder().decode(privateKeyString);
        // 创建私钥key的规则
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
        // 返回私钥对象
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 保存公钥和私钥，把公钥和私钥保存到根目录
     *
     * @param algorithm   算法
     * @param publicPath  公钥路径
     * @param privatePath 私钥路径
     */
    private static void generateKeyToFile(String algorithm, String publicPath, String privatePath) throws Exception {
        //
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // 生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 生成私钥
        PrivateKey privateKey = keyPair.getPrivate();
        // 生成公钥
        PublicKey publicKey = keyPair.getPublic();
        // 获取私钥的字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // 获取公钥字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        // 使用base64进行编码
        Base64.Encoder encoder = Base64.getEncoder();
        String privateEncodeString = encoder.encodeToString(privateKeyEncoded);
        String publicEncodeString = encoder.encodeToString(publicKeyEncoded);
        // 把公钥和私钥保存到根目录
        FileUtils.writeStringToFile(new File(publicPath), publicEncodeString, StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(privatePath), privateEncodeString, StandardCharsets.UTF_8);
    }

    /**
     * 解密数据
     *
     * @param algorithm 算法
     * @param publicKey 密钥
     * @param encrypted 密文
     * @return 原文
     * @throws Exception
     */
    private static String decryptRSA(String algorithm, Key publicKey, String encrypted) throws Exception {
        // 创建解密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        // 私钥解密
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        byte[] decoded = Base64.getDecoder().decode(encrypted);
        // 使用私钥进行解密
        byte[] decrypted = cipher.doFinal(decoded);
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * 使用密钥加密数据
     *
     * @param algorithm  算法
     * @param privateKey 密钥
     * @param input      原文
     * @return 密文
     * @throws Exception
     */
    private static String encryptRSA(String algorithm, Key privateKey, String input) throws Exception {
        // 创建加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        // 对加密进行初始化
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        // 使用私钥进行加密
        byte[] bytes = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(bytes);
    }
}
